package com.egao.common.module.system.controller;

import cn.hutool.core.util.StrUtil;
import com.egao.common.core.Constants;
import com.egao.common.core.log.LogCas;
import com.egao.common.core.security.JwtUtil;
import com.egao.common.core.web.BaseController;
import com.egao.common.module.system.entity.LoginRecord;
import com.egao.common.module.system.entity.User;
import com.egao.common.module.system.service.LoginRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.jasig.cas.client.util.XmlUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * 登录接口
 * @author lym
 */
@Api(tags = "登录")
@RestController
@RequestMapping("${api}")
public class LoginController extends BaseController {

    @Autowired
    private LoginRecordService loginRecordService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${vue.server}")
    private String vueServer;
    @Value("${vue.authorization}")
    private String vueAuthorization;

    @ApiOperation(value = "账号密码登录", notes = "登录操作由JwtLoginFilter完成")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "账号", required = true, dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "string", paramType = "query"),
    })
    @PostMapping("/login")
    public void login() {
    }

    @ApiOperation(value = "单点登录", notes = "用户点击单点登录后到Cas登录界面，在Cas登录界面登录成功后重定向到本接口，本接口获取到用户构建token重定向到前端")
    @GetMapping("/login/cas")
    public void loginCas(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String ticket = request.getParameter("ticket");
        String p = request.getParameter("p");
        User user = getLoginUser();
        if (user != null) {
            // 生成登录用户的token
            String accessToken = JwtUtil.buildToken(user.getUsername(), Constants.TOKEN_EXPIRE_TIME, Constants.TOKEN_KEY);

            // 缓存登录用户的票据 12小时 - 保证时间大于Cas服务器的存储时间 即使是自然登出，也可以再后续Cas服务注销时找的到值
            redisTemplate.opsForValue().set(ticket, user.getUsername(), 12, TimeUnit.HOURS);

            // 缓存用户登录状态 无限制时间
            redisTemplate.opsForValue().set(user.getUsername(), Constants.CAS_LOGIN_MARK);

            // 登录记录
            loginRecordService.saveAsync(user.getUsername(), LoginRecord.TYPE_LOGIN, "CAS", request);

            LogCas.info("单点登录TOKEN:" + accessToken);

            // 重定向到前端授权页面
            if ("m".equals(p)) {
                LogCas.info("单点登录移动端跳转");
                response.sendRedirect("https://jyzx.zuel.edu.cn/m/#/wechat/cas?tk=" + accessToken);
            } else {
                LogCas.info("单点登录PC端跳转");
                response.sendRedirect(vueAuthorization + accessToken);
            }
        } else {
            // 扫码情况会第一次默认没有用户 再次重定向到CAS登录接口会有用户再重定向到具体地址
            response.sendRedirect("https://ids.zuel.edu.cn/authserver/login?service=https://jyzx.zuel.edu.cn/api/login/cas");
        }
    }

    @ApiOperation(value = "单点登出", notes = "用户登出访问Cas登出地址，Cas处理完成重定向到本接口再重定向到前端首页")
    @GetMapping("/login/cas/logout")
    public void ssoLogout(HttpServletResponse response) throws IOException {
        response.sendRedirect(vueServer);
    }

    @ApiOperation(value = "监听Cas服务注销", notes = "其他Cas客户端登出时，服务端发起请求本接口，接口处理登出用户本系统的授权作废操作")
    @PostMapping("/login/cas")
    public void ssoLoginPost(HttpServletRequest request) {
        // 获取ticket
        String logoutRequest = request.getParameter("logoutRequest");
        String ticket = XmlUtils.getTextForElement(logoutRequest, "SessionIndex");

        // 根据ticket获取用户
        String userName = redisTemplate.opsForValue().get(ticket);
        if (!StrUtil.isBlank(userName)) {
            // 设置用户为登出状态
            redisTemplate.opsForValue().set(userName, Constants.CAS_LOGOUT_MARK);

            // 清除ticket
            redisTemplate.delete(ticket);
        }
    }

}
